#include "RayTracingProcessor.h"
#include <algorithm/rayTracing/dataLoader/SceneConfiguration.h>
#include <algorithm/rayTracing/dataLoader/SceneField.h>
#include <algorithm/rayTracing/dataLoader/SceneLoader.h>
#include <algorithm/rayTracing/rayTracingDataStructure/grid/CudaRectangleGrid.cuh>
#include <algorithm/rayTracing/rayTracingDataStructure/heliostat/CudaRectangleHelio.cuh>
#include <algorithm/rayTracing/rayTracingDataStructure/receiver/CudaCylinderReceiver.cuh>
#include <algorithm/rayTracing/rayTracingDataStructure/receiver/CudaMultiPanelReceiver.cuh>
#include <algorithm/rayTracing/rayTracingDataStructure/receiver/CudaRectangleReceiver.cuh>
#include <algorithm/rayTracing/rayTracingDataStructure/receiver/CudaRefinedCylinderReceiver.cuh>
#include <algorithm/rayTracing/rayTracingDataStructure/receiver/CudaRefinedRectangleReceiver.cuh>
#include <algorithm/rayTracing/rayTracingDataStructure/sunRay/CudaSunRay.cuh>
#include <algorithm/rayTracing/rayTracingPipeline/RayTracingPipeline.h>
#include <algorithm/shared/data/scene/Heliostat.h>
#include <algorithm/shared/data/scene/Node.h>
#include <algorithm/shared/data/scene/Receiver.h>
#include <algorithm/shared/data/scene/Sun.h>
#include <algorithm/shared/data/topology/geometry/Cylinder.h>
#include <algorithm/shared/data/topology/geometry/MultiPanel.h>
#include <algorithm/shared/data/topology/geometry/Rectangle.h>
#include <algorithm/shared/data/topology/geometry/RefinedCylinder.h>
#include <algorithm/shared/data/topology/geometry/RefinedRectangle.h>
#include <algorithm/shared/data/world/sun/sun_position/SunPosition.h>
#include <algorithm/shared/utils/Grid.h>
#include <ui/scene/Scene.h>
#include <ui/tree/ParaTreeModel.h>
#include <ui/tree/TopoTreeNode.h>
#include <ui/tree/TopoTreeViewController.h>
#include <ui/window/dataVisualizationWindow/ColorMap.h>
#include <ui/window/simulationWindow/RayTracingParameter.h>
#include <utils/ParaUtils.h>


#include <boost/gil.hpp>
#include <boost/gil/extension/io/png.hpp>
#include <boost/gil/image.hpp>
#include <boost/gil/image_view.hpp>
#include <boost/gil/io/io.hpp>
#include <boost/gil/typedefs.hpp>
#include <boost/unordered/unordered_flat_map.hpp>

#include <boost/json.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>

#include <QColor>
#include <QDebug>
#include <QImage>
#include <QLinearGradient>
#include <QPainter>

#include <utility>

using namespace boost::gil;
// using namespace boost::json;
using namespace solar;

/*
bool RayTracingProcessor::rayTracing()
{

    std::cout << "raytracing in Processor begins" << std::endl;
    raytracing_pipeline_->rayTracing();     // 执行光追
    std::cout << "raytracing in Processor ends" << std::endl;

    return true;
}

bool RayTracingProcessor::plotFluxMap()
{
    raytracing_pipeline_->plotFluxMap();

    return true;
}
*/
/*

bool RayTracingProcessor::plotFluxMap()
{
    // 把raytracing_pipeline_中的result_data中的相应数据保存在flux_map_paras_中

    std::string flux_map_name = "flux_map.png";
    auto result_data = raytracing_pipeline_->getResultData();

    // 画图
    std::cout <<"============image plotting in RayTracingProcessor begin====================" <<
std::endl; int2 resolution = result_data.resolution; float* data = result_data.data_p_after_smooth;
    std::cout <<"resolution = " << resolution.x << "," <<resolution.y <<std::endl;
    int width = resolution.x;
    int height = resolution.y;

    ColorMap colormap;      // 用于jet颜色映射
    colormap.setMinMax(0.0, result_data.maximum_flux * 1000);   //
result_data.maximum_flux单位是kW/m^2

    QColor color;
    boost::gil::rgb8_image_t img(width, height);
    auto img_view = view(img);
    rgb8_pixel_t pixel;

    for(int i = 0 ; i < height ; i++)
    {
        for(int j = 0 ; j < width ; j++)
        {
            int current_index = i * width + j ;
            float current_flux = data[current_index] ;

            color = colormap.getColor(current_flux);
            pixel[0] = static_cast<std::uint8_t>(color.red());
            pixel[1] = static_cast<std::uint8_t>(color.green());
            pixel[2] = static_cast<std::uint8_t>(color.blue());

            if(current_flux > 1e-5) {
                // std::cout <<current_flux<<",(" <<color.red() <<","<<color.green()
<<","<<color.blue()<<"),"
                //     << "pixel (" << i << "," << j << "): (" << +pixel[0] << "," << +pixel[1] <<
"," << +pixel[2] << ")\n";
            }
            img_view(j,i) = pixel;
        }
    }
    write_view(flux_map_name, img_view, png_tag());

    std::cout <<"============image plotting end====================" << std::endl;

    // flux_map_paras_->cppSetTotalPower(result_data.total_power);
    // flux_map_paras_->cppSetMaximumFlux(result_data.maximum_flux);
    // flux_map_paras_->cppSetMaximumFluxLocationX(result_data.maximum_location.x);
    // flux_map_paras_->cppSetMaximumFluxLocationY(result_data.maximum_location.y);
    // flux_map_paras_->cppSetPixelNumX(result_data.resolution.x);
    // flux_map_paras_->cppSetPixelNumY(result_data.resolution.y);

    // std::cout <<"result_data.maximum_flux = "<<result_data.maximum_flux
    //             <<" location =
"<<result_data.maximum_location.x<<","<<result_data.maximum_location.y<<std::endl;
    // std::cout <<"flux_map_paras.maximum_flux = "<< flux_map_paras_->getMaximumFlux()
    //             <<" location = "<<flux_map_paras_->getMaximumFluxLocationX()
<<","<<flux_map_paras_->getMaximumFluxLocationY()<<std::endl;
    // std::string flux_map_path = "qrc:/build/";
    // flux_map_path = flux_map_path + flux_map_name;
    // flux_map_paras_->cppSetFluxMapPath(QString::fromStdString(flux_map_path));
        // auto result_data = raytracing_pipeline_->getResultData();

    // float* data = result_data.data_p_after_smooth;

    return true;
}
*/

using namespace solar;
namespace pt = boost::property_tree;

RayTracingProcessor::RayTracingProcessor()
{
    // raytracing_pipeline_ = std::make_shared<RayTracingPipeline>() ;
    field_ = std::make_shared<SceneField>();
    config_ = std::make_shared<SceneConfiguration>();
};

bool RayTracingProcessor::updateRayTracingPipelineData(
    std::shared_ptr<Scene> scene, std::shared_ptr<RayTracingParameter> simulation_paras)
{
    std::cout << "RayTracingProcessor::updateRayTRacingPipelineData::begin loadConfig()"
              << std::endl;
    // qDebug() << (raytracing_pipeline_->getConfiguration()).get();
    loadConfig(config_, scene, simulation_paras);

    // qDebug() << (raytracing_pipeline_->getConfiguration()).get();

    std::cout << "RayTracingProcessor::updateRayTRacingPipelineData::begin loadField()"
              << std::endl;
    loadField(field_, scene, simulation_paras);

    // std::cout << "pipeline set field\n";
    // if(raytracing_pipeline_ == nullptr){std::cout <<"raytracing pipeline ==nullptr\n";}
    // raytracing_pipeline_->setSceneField(field_);
    // std::cout << "pipeline setconfig\n";
    // raytracing_pipeline_->setConfiguration(config_);
    // std::cout << "pipeline all set\n";
    return true;
}

auto RayTracingProcessor::loadField(std::shared_ptr<SceneField>& field,
                                    std::shared_ptr<Scene> scene,
                                    std::shared_ptr<RayTracingParameter> simulation_paras) -> bool
{
    qDebug() << "4444";
    auto* topo_tree_node =
        scene->topo_tree_control_->getTopoTreeModel()->getRootNode()->child(0).get();
    float3 position{0, 0, 0};
    std::cout << "RayTracingProcessor::loadField::begin setHelioAndRevRecursively()" << std::endl;
    setHelioAndRevRecursively(field, topo_tree_node, position);

    std::cout << "RayTracingProcessor::loadField::begin setSunray()" << std::endl;
    setSunray(field, config_); // 先设置sunray
    std::cout << "RayTracingProcessor::loadField::begin setGrid()" << std::endl;
    setGrid(field, simulation_paras);
    std::cout << "RayTracingProcessor::loadField::end setGrid()" << std::endl;
    return true;
}
auto RayTracingProcessor::loadConfig(std::shared_ptr<SceneConfiguration>& config,
                                     std::shared_ptr<Scene> scene,
                                     std::shared_ptr<RayTracingParameter> simulation_paras) -> bool
{
    qDebug() << "222222";
    //------------begin set properties from SunPosition-------------
    auto* sun_ptr = scene->getSun();
    auto sun_position_ptr = SOLAR_GET_VALUE(Sun, sun_position_, *sun_ptr);
    auto sun_azimuth = SOLAR_GET_VALUE(SunPosition, azimuth_, *sun_position_ptr);
    qDebug() << "1";
    qDebug() << config.get();

    config->setSunAzimuth(sun_azimuth);
    qDebug() << "2";
    auto sun_altitude = SOLAR_GET_VALUE(SunPosition, elevation_, *sun_position_ptr);
    config->setSunAltitude(sun_altitude);
    // ！！！！！！先暂时把irradiance设置为dni（不太清楚两个参数之间有什么区别，先这样设置）
    auto dni = SOLAR_GET_VALUE(SunPosition, dni_, *sun_position_ptr);
    config->setDni(dni);
    auto csr = 0.1; // !!!!!!csr暂时设置为0.1
    config->setCsr(csr);
    //------------end set properties from SunPosition----------

    //-----------begin set properties from RayTracingParameter-----------------
    setConfigFromRayTracingParameter(config, simulation_paras);

    //-------------end set properties from RayTracingParameter-------------------

    //-------------？？？？？？？是否要从scene中读取一个定日镜材质来设置disturb_std和reflected_rate呢？？？？？--------------
    // disturb_std 需要从某个定日镜的材质中获得 !!!!!!
    // reflected_rate 需要从某个定日镜的材质中获得!!!!!!!

    return true;
}

void RayTracingProcessor::setConfigFromRayTracingParameter(
    std::shared_ptr<SceneConfiguration>& config,
    std::shared_ptr<RayTracingParameter> simulation_paras)
{
    /**
     * TODO::add different kind of sunshape
     * */
    qDebug() << "3333";
    auto num_sunshape_groups = simulation_paras->getNumSunshapeGroups();
    config->setNum_sunshape_groups(num_sunshape_groups);
    auto num_sunshape_lights_per_group = simulation_paras->getNumSunshapeLightsPerGroup();
    std::cout << "num of lights per group = " << num_sunshape_lights_per_group << std::endl;
    config->setNum_sunshape_lights_per_group(num_sunshape_lights_per_group);
    auto inverse_transform_sampling_groups = simulation_paras->getInverseTransformSamplingGroups();
    config->setInverse_transform_sampling_groups(inverse_transform_sampling_groups);
    auto receiver_pixel_length = simulation_paras->getPixelLength();
    config->setReceiver_pixel_length(receiver_pixel_length);
    auto helio_pixel_length = simulation_paras->getMicroheliostatLength();
    config->setHelio_pixel_length(helio_pixel_length);

    /**
     * 注意，这里不需要再从simulation_paras中获取，可以直接从json文件中获取-----即不再需要simulation_paras这一参数
     */
}

void RayTracingProcessor::setRayTracingPipeline(
    std::shared_ptr<RayTracingPipeline> raytracing_pipeline)
{
    // std::cout << "================set raytracing_pipeline_============================\n";
    raytracing_pipeline_ = std::move(raytracing_pipeline);
    if (raytracing_pipeline_ == nullptr)
    {
        // std::cout << "-----------raytracing pipeline ==nullptr\n";
    }
}

auto RayTracingProcessor::loadCloudFilePath() -> bool
{
    // Cloud* cloud_ptr = scene_->getCloud();
    // auto grid_ptr = solar::getPara(toMemberName("grid"),
    // cloud_ptr).value<std::shared_ptr<Grid>>(); std::string filepath =
    // solar::getPara(toMemberName("file"), grid_ptr.get()).toString().toStdString();

    // // ！！！！添加：判断路径是否可以打开

    // raytracing_pipeline_->setCloudFilePath(filepath);

    return true;
}

/**
 * configuration中已经保存了sunray的相关信息，这里只是生成一个sunray对象，并存到field中
 */
bool RayTracingProcessor::setSunray(std::shared_ptr<SceneField>& field,
                                    std::shared_ptr<SceneConfiguration> configu)
{
    std::shared_ptr<cuda::CudaSunray> sunray = std::make_shared<cuda::CudaSunray>();
    sunray->setSunDirection(configu->getSun_dir());

    /**
     * TODO:: add different type of sunshape
     * */
    sunray->setCSR(configu->getCsr());
    sunray->setDNI(configu->getDni());
    sunray->setNumOfSunshapeGroups(configu->getNum_sunshape_groups());
    sunray->setNumOfSunshapeLightsPerGroup(configu->getNum_sunshape_lights_per_group());
    sunray->setReflectiveRate(
        configu
            ->getReflected_rate()); // ！！！！！！这里的反射率是sceneconfiguration中默认设置，不是从定日镜上读取的！！！！

    field->setSunRay(sunray);
    return true;
}
bool RayTracingProcessor::setGrid(std::shared_ptr<SceneField>& field,
                                  std::shared_ptr<RayTracingParameter> simulation_paras)
{
    // // 整个场景只有一个Grid
    auto ground_length = simulation_paras->getGroundLength();
    auto ground_width = simulation_paras->getGroundWidth();
    field->setGroundLength(ground_length);
    field->setGroundWidth(ground_width);

    std::shared_ptr<cuda::CudaGrid> grid = std::make_shared<cuda::CudaRectangleGrid>();
    grid->setGridType(0);
    grid->setBelongingReceiverIndex(0); //!!!!属于哪个接收器，目前只有一个接收器
    grid->setStartHeliostatIndex(
        0); //!!!!网格内开始 的定日镜序号，只有一个网格，网格内有所有的定日镜

    Vec3 pos = simulation_paras->getGridPos();
    Vec3 size = simulation_paras->getGridSize();
    Vec3 interval = simulation_paras->getGridInterval();
    grid->setPosition(float3(pos.x(), pos.y(), pos.z()));
    grid->setSize(float3(size.x(), size.y(), size.z()));
    grid->setInterval(float3(interval.x(), interval.y(), interval.z()));

    /**
     *  TODO:: process all kinds of helio
     */
    grid->setNumberOfHeliostats(
        field->getHeliostats().size()); // ！！！！！！！！！！！先放一个定日镜
    grid->setHeliostatType(0); // ！！！！！！！！！！！定日镜类型暂时定为0---目前只有矩形定日镜

    field->addGrid(grid);
    return true;
}
void RayTracingProcessor::setHelioAndRevRecursively(std::shared_ptr<SceneField>& field,
                                                    TopoTreeNode*& root, float3 position)
{

    int topo_node_type = root->getParaModelType(); // 类型：NODE,HELIO,REV,ORDINARY

    Para* para = root->getParaTreeModel()->getParaPtr();
    switch (topo_node_type)
    {
    case NODE: // node---改变position，接着往下遍历
    {
        auto* node_ptr = dynamic_cast<Node*>(para);
        auto translation = SOLAR_GET_VALUE(Node, translation_, *node_ptr);
        // Rotation rotation = node_ptr->getPara(toMemberName("rotation")).value<Rotation>();
        // Vec3 scale = node_ptr->getPara(toMemberName("scale")).value<Vec3>();

        // 设置heliostat和receiver时，只需要translation即可，不需要rotation和scale

        auto child_cnt = root->childCount();
        for (int i = 0; i < child_cnt; ++i)
        {
            auto* child_node = root->child(i).get();
            setHelioAndRevRecursively(
                field, child_node,
                position + float3(translation.x(), translation.y(), translation.z()));
        }

        break;
    }
    case HELIOSTAT: // heliostat----记录位置，找到对应的para
    {
        setOneHeliostat(field, para, position);
        break;
    }
    case RECEIVER: // receiver
    {
        setOneReceiver(field, para, position);
        break;
    }
    case ORDINARY: // ordinary---不做任何处理
    {
        break;
    }
    default:
    {
        throw "ERROR::SceneField::recruiseGetHelioAndRev::do not have this topo_node_type";
    }
    }
}
void RayTracingProcessor::setOneHeliostat(std::shared_ptr<SceneField>& field, Para*& para,
                                          float3 position)
{
    auto* heliostat_ptr = dynamic_cast<Heliostat*>(para);
    std::shared_ptr<cuda::CudaHeliostat> helio;

    std::cout << "setOneHeliostat() begins \n";

    //---------------------geometry-------------------
    //
    /**
     * TODO:: add other geometries
     */
    auto geometry_ptr = SOLAR_GET_VALUE(Heliostat, geometry_, *heliostat_ptr);
    // std::cout <<"setOneHeliostat()::get geometry_ptr: " << geometry_ptr << std::endl;
    GeometryType geometry_type = geometry_ptr->getType();
    // std::cout <<" setOneHeliostat()::switch begins: "<<geometry_type <<" target:
    // "<<GeometryType::kGeometryRectangle<< std::endl;

    // auto geometry = std::any_cast< boost::unordered::unordered_flat_map<GeometryType,
    // std::shared_ptr<Geometry>> >
    //                     (solar::getParaAsAny(toMemberName("geometry"), heliostat_ptr));
    // GeometryType geometry_type =
    // std::any_cast<GeometryType>(solar::getParaAsAny(toMemberName("geometry_type"),
    // heliostat_ptr));
    switch (geometry_type)
    {
    /**
     * TODO: add otther types of helio,
     *          B-Spline Surface .i.e
     */
    // 假设定日镜均为rectangle类型
    // ！！！！！！！这里设置的参数并不全！！！！！！！！！先把demo跑通，以后再改
    case GeometryType::kGeometryRectangle:
    {
        std::cout
            << "---------------setOneHeliostat()::geometry rectangle begin-------------------- \n";
        helio = std::make_shared<cuda::CudaRectangleHelio>();
        auto* rectangle_geometry_ptr = dynamic_cast<Rectangle*>(geometry_ptr.get());

        // 设置helio的参数
        auto gap = SOLAR_GET_VALUE(Heliostat, gap_, *heliostat_ptr);
        helio->setGap(float2(gap.x(), gap.y()));
        auto subheliostat_row_col = SOLAR_GET_VALUE(Heliostat, subhelio_row_col_, *heliostat_ptr);
        helio->setRowAndColumn(int2(subheliostat_row_col.x(), subheliostat_row_col.y()));
        helio->setPosition(position);

        float thickness = SOLAR_GET_VALUE(Heliostat, thickness_, *heliostat_ptr);
        auto rect_size = SOLAR_GET_VALUE(Rectangle, size_, *rectangle_geometry_ptr);
        std::cout << "=== rect_size = " << rect_size.x() << "," << rect_size.y() << std::endl;
        // !!!!!!!!!!!注意这里的顺序，thickness在y轴上
        float3 size(rect_size.x(), thickness, rect_size.y());
        // ui中的rectangle，size只有两个维度，第三个维度用heliostat的thickness补上
        helio->setSize(size);
        helio->setShift(0);

        auto heliopos = helio->getPosition();
        auto heliosize = helio->getSize();
        std::cout << "\t helio position = " << heliopos.x << " " << heliopos.y << " " << heliopos.z
                  << std::endl;
        std::cout << "\t helio size = " << heliosize.x << " " << heliosize.y << " " << heliosize.z
                  << std::endl;
        std::cout
            << "--------------setOneHeliostat()::geometry rectangle end-------------------- \n";

        break;
    }

    default:
    {
        break;
    }
    }

    //-------------------material--貌似暂时用不上-----------------------
    // auto material_ptr =
    // heliostat_ptr->getPara(toMemberName("material")).value<std::shared_ptr<Material>>();
    // ------------????????是否读取材质属性，为config赋值????????????----------

    helio->setBelongingGridId(0);
    field->addHeliostat(helio);
}

void RayTracingProcessor::setOneReceiver(std::shared_ptr<SceneField>& field, Para*& para,
                                         float3 position)
{
    auto receiver_ptr = dynamic_cast<Receiver*>(para);
    std::shared_ptr<cuda::CudaReceiver> rev;

    std::cout << "setOneReceiver() begins \n";

    std::cout << "setOneREceiver()::receiver_ptr: " << receiver_ptr << std::endl;

    /**
     * 问题： 当改变rev的geometry类型后，没有生成新的类型
     */
    auto geometry_ptr = SOLAR_GET_VALUE(Receiver, geometry_, *receiver_ptr);
    // std::cout <<"setOneReceiver()::get geometry_ptr: " << geometry_ptr << std::endl;
    GeometryType geometry_type = geometry_ptr->getType();
    // std::cout <<" setOneReceiver()::get geometry type: "<< geometry_type << std::endl;
    // std::cout <<" setOneReceiver()::switch begins: "<<geometry_type <<" target:
    // "<<(int)GeometryType::kGeometryCylinder<< std::endl;

    // auto geometry = std::any_cast< boost::unordered::unordered_flat_map<GeometryType,
    // std::shared_ptr<Geometry>> >
    //                     (solar::getParaAsAny(toMemberName("geometry"), receiver_ptr));
    // GeometryType geometry_type =
    // std::any_cast<GeometryType>(solar::getParaAsAny(toMemberName("geometry_type"),
    // receiver_ptr));
    switch (geometry_type)
    {
    /**
     *
     * receiver type:
     *          0 - rectangle
     *          1 - cylinder
     *          2 - RefinedRectangle    --- 没有写
     *          3 - RefinedCylinder     --- 是heat tube
     *          4 - MultiPanel
     *
     * TODO: add other types of rev
     */
    case GeometryType::kGeometryRectangle:
    {
        std::cout << "------------setOneReceiver()::geometry rectangle begin-------------- \n";

        auto* rectangle_geometry_ptr = dynamic_cast<Rectangle*>(geometry_ptr.get());

        rev = std::make_shared<cuda::CudaRectangleReceiver>();
        rev->setType(0);
        rev->setPosition(position);
        auto size = SOLAR_GET_VALUE(Rectangle, size_, *rectangle_geometry_ptr);
        rev->setSize(float3(size.x(), size.y(), 0));
        rev->setSurfaceIndex(
            0); // ！！！！！！！！！！！surface_index指的是surface的朝向，0-5分别代表朝向3个轴的正负轴
        rev->setNormal(float3(0, 0, -1)); // ！！！！！！！！！！！！！normal指的是什么？？？
        // auto revpos = rev->getPosition();
        // auto revsize = rev->getSize();
        // auto revnorm = rev->getNormal();
        // std::cout <<"\t rev position = " << revpos.x <<" " << revpos.y <<" "<<revpos.z <<
        // std::endl; std::cout <<"\t rev size = " << revsize.x << " " << revsize.y << " "
        // <<revsize.z << std::endl; std::cout <<"\t rev norm = " << revnorm.x << " " << revnorm.y
        // << " " <<revnorm.z << std::endl;
        std::cout << "------------setOneReceiver()::geometry rectangle end-------------- \n";
        break;
    }

    case GeometryType::kGeometryCylinder:
    {
        std::cout << "--------------setOneReceiver()::geometry cylinder begin------------ \n";

        auto* cylinder_geometry_ptr = dynamic_cast<Cylinder*>(geometry_ptr.get());

        rev = std::make_shared<cuda::CudaCylinderReceiver>();
        rev->setType(1); //!!!!!!!!!!!按照算法的枚举类型来设置，cylinder的type为1
        rev->setPosition(position);
        // std::cout << "rev-position: " << position.x << "," << position.y << "," <<position.z <<
        // std::endl;

        // 设置size
        auto height = SOLAR_GET_VALUE(Cylinder, height_, *cylinder_geometry_ptr);
        auto radius = SOLAR_GET_VALUE(Cylinder, radius_, *cylinder_geometry_ptr);
        // std::cout <<"---------------cylinder receiver height = "<<height<<",  radius = "<<radius
        // << std::endl;
        rev->setSize(float3(radius, height, 0));
        // !!!!!!!!!!其他参数不清楚该怎么设置，等到用到的时候再说！！！！！！！！！！！！！！！！！！！
        std::cout << "--------------setOneReceiver()::geometry cylinder end-------------- \n";
        break;
    }

    case GeometryType::kGeometryRefinedRectangle:
    {
        std::cout
            << "------------setOneReceiver()::geometry refined rectangle begin-------------- \n";

        auto* refined_rectangle_geometry_ptr = dynamic_cast<RefinedRectangle*>(geometry_ptr.get());
        rev = std::make_shared<cuda::CudaRefinedRectangleReceiver>();
        rev->setType(2);
        rev->setPosition(position);

        auto size = SOLAR_GET_VALUE(RefinedRectangle, size_, *refined_rectangle_geometry_ptr);
        rev->setSize(float3(size.x(), size.y(), 0));
        rev->setSurfaceIndex(0); //!!!!!!!!!!!surface index和normal以后或许会加到ui界面中区
        rev->setNormal(float3(0, 0, -1)); //!!!!!!!!!!!

        // int tube = refined_rectangle_geometry_ptr->getPara(toMemberName("tube")).toInt();
        // int panel = refined_rectangle_geometry_ptr->getPara(toMemberName("panel")).toInt();
        // int tube_unit =
        // refined_rectangle_geometry_ptr->getPara(toMemberName("tube_unit")).toInt();
        auto tube_radius =
            SOLAR_GET_VALUE(RefinedRectangle, tube_radius_, *refined_rectangle_geometry_ptr);
        // rev->setTube(tube);
        // rev->setPanel(panel);
        // rev->setTubeUnit(tube_unit);
        rev->setRadius(tube_radius);
        std::cout
            << "------------setOneReceiver()::geometry refined rectangle end-------------- \n";

        break;
    }

    case GeometryType::kGeometryRefinedCylinder:
    {
        std::cout
            << "------------setOneReceiver()::geometry refined cylinder begin-------------- \n";
        auto* refined_cylinder_geometry_ptr = dynamic_cast<RefinedCylinder*>(geometry_ptr.get());

        rev = std::make_shared<cuda::CudaRefinedCylinderReceiver>();
        rev->setType(3); //!!!!!!!!!!!按照算法的枚举类型来设置，cylinder的type为1
        rev->setPosition(position);

        // 设置size
        auto height = SOLAR_GET_VALUE(RefinedCylinder, height_, *refined_cylinder_geometry_ptr);
        auto radius = SOLAR_GET_VALUE(RefinedCylinder, radius_, *refined_cylinder_geometry_ptr);
        rev->setSize(float3(radius, height, 0));

        auto tube = SOLAR_GET_VALUE(RefinedCylinder, tube_, *refined_cylinder_geometry_ptr);
        auto panel = SOLAR_GET_VALUE(RefinedCylinder, panel_, *refined_cylinder_geometry_ptr);
        auto tube_unit =
            SOLAR_GET_VALUE(RefinedCylinder, tube_unit_, *refined_cylinder_geometry_ptr);
        auto tube_radius =
            SOLAR_GET_VALUE(RefinedCylinder, tube_radius_, *refined_cylinder_geometry_ptr);
        rev->setTube(tube);
        rev->setPanel(panel);
        rev->setTubeUnit(tube_unit);
        rev->setRadius(tube_radius);

        std::cout << "------------setOneReceiver()::geometry refined cylinder end-------------- \n";

        break;
    }

        // case GeometryType::kGeometryMultiPanel:
        // {
        //     std::cout <<"------------setOneReceiver()::geometry multi panel begin--------------
        //     \n"; auto multipanel_geometry_ptr = dynamic_cast<MultiPanel*>(geometry_ptr.get());

        //     rev = std::make_shared<MultiPanelReceiver>();
        //     rev->setType(4);        //!!!!!!!!!!!按照算法的枚举类型来设置，cylinder的type为1
        //     rev->setPosition(position);

        //     //!!!!!!!! setSize;
        //     auto size = multipanel_geometry_ptr->getPara(toMemberName("size")).value<Vec2>();
        //     rev->setSize(float3(size.x(), size.y(), 0));

        //     int tube = multipanel_geometry_ptr->getPara(toMemberName("tube")).toInt();
        //     int panel = multipanel_geometry_ptr->getPara(toMemberName("panel")).toInt();
        //     int tube_unit = multipanel_geometry_ptr->getPara(toMemberName("tube_unit")).toInt();
        //     float tube_radius =
        //     multipanel_geometry_ptr->getPara(toMemberName("tube_radius")).toFloat();
        //     rev->setTube(tube);
        //     rev->setPanel(panel);
        //     rev->setTubeUnit(tube_unit);
        //     rev->setRadius(tube_radius);

        //     std::cout <<"------------setOneReceiver()::geometry multi panel end--------------
        //     \n";

        //     break;
        // }

    default:
    {
        break;
    }
    }

    field->addReceiver(rev);
}

bool RayTracingProcessor::updateRayTracingPipelineData(
    std::string file_path, std::shared_ptr<RayTracingParameter> simulation_paras)
{
    // read_json(raytracing_pipeline_->getConfiguration(),raytracing_pipeline_->getSceneField(),file_path);
    // loadConfig(raytracing_pipeline_->getConfiguration(), file_path, simulation_paras);
    // loadField(raytracing_pipeline_->getSceneField(), file_path, simulation_paras);
    read_json(config_, field_, file_path);
    setSunray(field_, config_);
    // loadConfig(config_, file_path, simulation_paras);
    // loadField(field_, file_path, simulation_paras);

    return true;
}

// bool RayTracingProcessor::loadField( std::shared_ptr<SceneField> &field, std::string file_path,
//                         std::shared_ptr<RayTracingParameter> simulation_paras)
// {
//     setSunray(field, config_);
//     // setGrid(field, simulation_paras);
//     return true;
// }

// bool RayTracingProcessor::loadConfig(std::shared_ptr<SceneConfiguration> &config,
//                         std::string file_path,
//                         std::shared_ptr<RayTracingParameter> simulation_paras)
// {
//     setConfigFromRayTracingParameter(config, simulation_paras);
//     return true;
// }

auto RayTracingProcessor::read_json(std::shared_ptr<SceneConfiguration>& config,
                                    std::shared_ptr<SceneField>& field,
                                    std::string file_path) -> bool
{
    std::ifstream ifs(file_path, std::ios_base::in);
    pt::ptree tree;
    pt::read_json(ifs, tree);

    std::cout << "根节点包含" << tree.size() << "个孩子节点" << std::endl;
    for (pt::ptree::iterator it = tree.begin(); it != tree.end(); ++it)
    {
        // if(it->first == "config")
        // {
        //     pt::ptree config_tree = tree.get_child(it->first);
        //     setConfigFromJSON(config, config_tree);
        // }
        if (it->first == "field")
        {
            pt::ptree field_tree = tree.get_child(it->first);
            setFieldFromJSON(field, field_tree);
        }
    }
    setConfigFromJSON(config, tree);
    setGridFromJSON(field, tree);
    return true;
}
void RayTracingProcessor::setGridFromJSON(std::shared_ptr<SceneField>& field, pt::ptree tree)
{
    pt::ptree simu_tree = tree.get_child("simulation");
    // // 整个场景只有一个Grid
    auto ground_length = simu_tree.get<float>("ground.x");
    auto ground_width = simu_tree.get<float>("ground.y");
    field->setGroundLength(ground_length);
    field->setGroundWidth(ground_width);

    std::shared_ptr<cuda::CudaGrid> grid = std::make_shared<cuda::CudaRectangleGrid>();
    grid->setGridType(0);
    grid->setBelongingReceiverIndex(0); //!!!!属于哪个接收器，目前只有一个接收器
    grid->setStartHeliostatIndex(
        0); //!!!!网格内开始 的定日镜序号，只有一个网格，网格内有所有的定日镜

    float pos_x = simu_tree.get<float>("grid.pos.x");
    float pos_y = simu_tree.get<float>("grid.pos.y");
    float pos_z = simu_tree.get<float>("grid.pos.z");
    float size_x = simu_tree.get<float>("grid.size.x");
    float size_y = simu_tree.get<float>("grid.size.y");
    float size_z = simu_tree.get<float>("grid.size.z");
    float interval_x = simu_tree.get<float>("grid.interval.x");
    float interval_y = simu_tree.get<float>("grid.interval.y");
    float interval_z = simu_tree.get<float>("grid.interval.z");
    grid->setPosition(float3(pos_x, pos_y, pos_z));
    grid->setSize(float3(size_x, size_y, size_z));
    grid->setInterval(float3(interval_x, interval_y, interval_z));

    /**
     *  TODO:: process all kinds of helio
     */
    grid->setNumberOfHeliostats(
        field->getHeliostats().size()); // ！！！！！！！！！！！先放一个定日镜
    grid->setHeliostatType(0); // ！！！！！！！！！！！定日镜类型暂时定为0---目前只有矩形定日镜

    field->addGrid(grid);
}

void RayTracingProcessor::setConfigFromJSON(std::shared_ptr<SceneConfiguration>& config,
                                            pt::ptree tree)
{

    std::cout << "setConfigFromJSON\n";
    // float azimuth = tree.get<float>("sun.sun_position.azimuth");
    // config->setSunAzimuth(azimuth);
    // float elevation = tree.get<float>("sun.sun_position.elevation");
    // config->setSunAltitude(elevation);
    // float dni = tree.get<float>("sun.sun_position.dni");
    // config->setDni(dni);
    // float csr = tree.get<float>("sun.sun_shape.csr");
    // config->setCsr(csr);
    pt::ptree simu_tree = tree.get_child("simulation");
    auto num_sunshape_groups = simu_tree.get<int>("num_sunshape_groups");
    config->setNum_sunshape_groups(num_sunshape_groups);
    auto num_sunshape_lights_per_group = simu_tree.get<int>("num_sunshape_lights_per_group");
    config->setNum_sunshape_lights_per_group(num_sunshape_lights_per_group);
    auto inverse_transform_sampling_groups =
        simu_tree.get<int>("inverse_transform_sampling_groups");
    config->setInverse_transform_sampling_groups(inverse_transform_sampling_groups);
    auto receiver_pixel_length = simu_tree.get<float>("receiver_pixel_length");
    config->setReceiver_pixel_length(receiver_pixel_length);
    auto helio_pixel_length = simu_tree.get<float>("heliostat_pixel_length");
    config->setHelio_pixel_length(helio_pixel_length);

    pt::ptree config_tree = tree.get_child("config");
    float azimuth = config_tree.get<float>("sun.sun_position.azimuth");
    config->setSunAzimuth(azimuth);
    float elevation = config_tree.get<float>("sun.sun_position.elevation");
    config->setSunAltitude(elevation);
    float dni = config_tree.get<float>("sun.sun_position.dni");
    config->setDni(dni);
    float csr = config_tree.get<float>("sun.sun_shape.csr");
    config->setCsr(csr);
    std::cout << "setConfigFromJSON over\n";
}
void RayTracingProcessor::setFieldFromJSON(std::shared_ptr<SceneField>& field, pt::ptree tree)
{
    std::cout << "setFieldFromJSON\n";
    pt::ptree receivers_tree = tree.get_child("receivers");
    setReceiverFromJSON(field, receivers_tree);
    pt::ptree heliostats_tree = tree.get_child("heliostats");
    setHeliostatFromJSON(field, heliostats_tree);
}
/**
 * 假设receiver只有一个
 * TODO::
 */
void RayTracingProcessor::setReceiverFromJSON(std::shared_ptr<SceneField>& field, pt::ptree tree)
{
    // for(pt::ptree::iterator it = tree.begin() ; it != tree.end() ; ++it)    // 遍历所有group
    // {
    //     pt::ptree group_tree = tree.get_child(it->first);

    // }
    std::cout << "setReceiverFromJSON\n";
    std::shared_ptr<cuda::CudaReceiver> rev;
    pt::ptree geometry_tree = tree.get_child("group.geometry");
    auto geometry_type = geometry_tree.get<std::string>("type");

    if (geometry_type == "rectangle")
    {
        std::cout << "set rev rectangle\n";
        rev = std::make_shared<cuda::CudaRectangleReceiver>();
        rev->setType(0);
        rev->setSurfaceIndex(0);
        rev->setNormal({0, 0, -1});
        auto size_x = geometry_tree.get<float>("size.x");
        auto size_y = geometry_tree.get<float>("size.y");
        rev->setSize({size_x, size_y, 0});
    }
    else if (geometry_type == "cylinder")
    {
        std::cout << "set rev cylinder\n";
        rev = std::make_shared<cuda::CudaCylinderReceiver>();
        rev->setType(1);
        auto height = geometry_tree.get<float>("height");
        auto radius = geometry_tree.get<float>("radius");
        rev->setSize({radius, height, 0});
    }
    else if (geometry_type == "refined_rectangle")
    {
        rev = std::make_shared<cuda::CudaRefinedRectangleReceiver>();
        rev->setType(2);
        rev->setSurfaceIndex(0);
        rev->setNormal({0, 0, -1});
        auto size_x = geometry_tree.get<float>("size.x");
        auto size_y = geometry_tree.get<float>("size.y");
        rev->setSize({size_x, size_y, 0});
        float tube_radius = geometry_tree.get<float>("tube_radius");
        rev->setRadius(tube_radius);
    }
    else if (geometry_type == "refined_cylinder")
    {
        rev = std::make_shared<cuda::CudaRefinedCylinderReceiver>();
        rev->setType(3);
        int tube = geometry_tree.get<int>("tube");
        int panel = geometry_tree.get<int>("panel");
        int tube_unit = geometry_tree.get<int>("tube_unit");
        auto tube_radius = geometry_tree.get<float>("tube_radius");
        rev->setTube(tube);
        rev->setPanel(panel);
        rev->setTubeUnit(tube_unit);
        rev->setRadius(tube_radius);
        auto height = geometry_tree.get<float>("height");
        auto radius = geometry_tree.get<float>("radius");
        rev->setSize({radius, height, 0});
    }

    auto normal_node = tree.get_child_optional("group.geometry.normal");
    if (normal_node.has_value())
    {
        rev->setNormal({normal_node->get<float>("x"), normal_node->get<float>("y"), normal_node->get<float>("z")});
    }

    auto pos_x = tree.get<float>("group.position.x");
    auto pos_y = tree.get<float>("group.position.y");
    auto pos_z = tree.get<float>("group.position.z");
    rev->setPosition({pos_x, pos_y, pos_z});

    field->addReceiver(rev);
}
void RayTracingProcessor::setHeliostatFromJSON(std::shared_ptr<SceneField>& field, pt::ptree tree)
{
    std::cout << "setHeliostatFromJSON\n";
    // pt::ptree group_tree = tree.get_child("group");
    for (pt::ptree::iterator it = tree.begin(); it != tree.end(); ++it)
    {
        pt::ptree group_tree = tree.get_child(it->first);

        pt::ptree geometry_tree = group_tree.get_child("geometry");
        auto geometry_type = geometry_tree.get<std::string>("type");
        auto size_x = geometry_tree.get<float>("size.x");
        auto size_y = geometry_tree.get<float>("size.y");
        auto thickness = group_tree.get<float>("thickness");
        float3 size = {size_x, thickness, size_y};
        auto gap_x = group_tree.get<float>("gap.x");
        auto gap_y = group_tree.get<float>("gap.y");
        int row = group_tree.get<int>("subhelio_row_col.row");
        int col = group_tree.get<int>("subhelio_row_col.col");

        pt::ptree differ_tree = group_tree.get_child("differ");
        for (auto differ_it = differ_tree.begin(); differ_it != differ_tree.end(); ++differ_it)
        {
            auto pos_x = differ_it->second.get<float>("position.x");
            auto pos_y = differ_it->second.get<float>("position.y");
            auto pos_z = differ_it->second.get<float>("position.z");

            std::shared_ptr<cuda::CudaHeliostat> helio =
                std::make_shared<cuda::CudaRectangleHelio>();
            helio->setSize(size);
            helio->setGap({gap_x, gap_y});
            helio->setPosition({pos_x, pos_y, pos_z});
            helio->setRowAndColumn({row, col});

            helio->setShift(0);
            helio->setBelongingGridId(0);

            field->addHeliostat(helio);
        }

        // if(group_tree.find("differ") != group_tree.not_found())
        // {
        //     pt::ptree differ_tree = group_tree.get_child("differ");
        //     int helio_num = differ_tree.size();
        //     for(auto differ_it = differ_tree.begin() ; differ_it != differ_tree.end();
        //     ++differ_it)
        //     {

        //     }

        // }
    }
}

// ResultData& RayTracingProcessor::getResultData()
// {
//     return raytracing_pipeline_->getResultData();
// }
